<template>
  <div class="content">
    <a-row type="flex" class="content-row">
      <!-- 索引列 -->
      <a-col flex="50px" class="col-index" v-show="showIndex">
        <!-- <a-checkbox> 全选 </a-checkbox> -->
        <ul>
          <li
            v-for="product in data"
            :key="product.key"
            :class="{ productActive: product.key == selectedIndex }"
            @click="indexClick(product.key)"
          >
            <!-- <a-checkbox></a-checkbox> -->
            <span>
              {{ product.name }}
              <!-- <a-badge
                :count="getSelectedCount(product)"
                :overflowCount="99999"
              /> -->
            </span>
          </li>
        </ul>
      </a-col>

      <a-col flex="auto" class="col-products">
        <a-row class="content-row">
          <a-col :span="5">
            <ul>
              <li>
                <a-checkbox
                  :checked="isCheckAllOfProductList(data, -2)"
                  @change="
                    (event) =>
                      checkAllProductList(event.target.checked, data, -1)
                  "
                >
                  全选
                </a-checkbox>
              </li>
            </ul>
            <ul>
              <li v-for="item in data" :key="item.key">
                <h4 v-if="showIndex">{{ item.key }}</h4>
                <dd>
                  <dl v-for="product in item.products" :key="product.key">
                    <!-- <a-checkbox

                  :checked="isCheckAllOfProduct(product, 0)"

                  @change="
                    (event.target.checked) =>
                      checkAllProductChildren(event.target.checked, product, product.key, 0)
                  "
                ></a-checkbox> -->

                    <span @click="productItemClick(product, product.key, 0)">
                      <span
                        :class="{
                          productActive:
                            selectedItems[0] &&
                            selectedItems[0].key == product.key,
                        }"
                        >{{ product.name }}</span
                      >
                      <a-badge
                        :count="getSelectedCount(product)"
                        :overflowCount="99999"
                    /></span>
                  </dl>
                </dd>
              </li>
            </ul>
          </a-col>
          <!--动态层级 -->
          <a-col
            v-for="levalItem in leval"
            :key="levalItem"
            :span="dynamicLevalSpans[levalItem - 1]"
          >
            <a-checkbox
              :checked="
                isCheckAllOfProductList(
                  productLists[levalItem - 1],
                  levalItem - 1
                )
              "
              @change="
                (event) =>
                  checkAllProductList(
                    event.target.checked,
                    productLists[levalItem - 1],
                    levalItem
                  )
              "
            >
              全选
            </a-checkbox>

            <ul>
              <li
                v-for="product in productLists[levalItem - 1]"
                :key="product.key"
              >
                <!-- <a-checkbox
              :checked="isCheckAllOfProduct(product, levalItem)"
              @change="
                (event) =>
                  checkAllProductChildren(
                    event.target.checked,
                    product,
                    product.key,
                    levalItem
                  )
              "
            ></a-checkbox> -->
                <span @click="productItemClick(product, product.key, levalItem)"
                  ><span
                    :class="{
                      productActive:
                        selectedItems[levalItem] &&
                        selectedItems[levalItem].key == product.key,
                    }"
                    >{{ product.name }}</span
                  ></span
                >
                <!-- 此处的统计是取子集的选中项 -->
                <a-badge
                  v-if="levalItem < leval"
                  :count="getSelectedCount(product)"
                  :overflowCount="99999"
                />
                <!-- 靠近最后一级的数量统计是直接统计选中项 -->
                <a-badge
                  else
                  :count="product.selectedKeys && product.selectedKeys.length"
                  :overflowCount="99999"
                />
              </li>
            </ul>
          </a-col>

          <!-- 动态层级 end -->

          <!-- 最后一列 -->
          <a-col :span="levalSpans[levalSpans.length - 1]">
            <a-checkbox
              :checked="selectedKeys.filter(key=>key.indexOf(selectedItems[leval-1].key)>-1).length ==
                    productLists[leval].length
              "
              @change="
                (event) =>
                  selectAll(event.target.checked, productLists[leval], leval)
              "
            >
              全选
            </a-checkbox>
            <ul>
              <li v-for="product in productLists[leval]" :key="product.key">
                <a-checkbox
                  :checked="selectedKeys.indexOf(product.key) >
                        -1
                  "
                  @click="selectItem(product, product.key, leval)"
                  >{{ product.name }}</a-checkbox
                >
              </li>
            </ul>
          </a-col>
        </a-row>
      </a-col>
    </a-row>

    <a-modal
      v-model="isShowSelected"
      width="70%"
      :footer="null"
      :mask="false"
      title="已选"
    >
      <div
        class="result"
        v-if="allSelectedProducts && allSelectedProducts.length > 0"
      >
        <a-table :columns="tableColums" :data-source="allSelectedProducts">
          <span slot="action" slot-scope="text, record">
            <a-button
              size="small"
              @click="
                deleteFromAllSeletedProducts(record.preProduct, record.key)
              "
              >删除</a-button
            >
          </span>
        </a-table>
      </div>
    </a-modal>
    <a-button @click="isShowSelected = true">显示已选</a-button>
  </div>
</template>

<script>
export default {
  props: {
    // 是否显示索引：索引 即 A B C  那层
    showIndex: {
      type: Boolean,
      default: true,
    },
    levalCount: {
      type: Number,
      validator(value) {
        return value >= 3;
      },
      default() {
        return 4;
      },
    },
    levalSpans: {
      type: Array,
      default() {
        return [3, 4, 5, 5, 7];
      },
    },
    dataLoader: {
      type: Function,
      default(product, key, leval, callback) {
        var products = [];
        //模拟查询数据
        for (let i = 0; i < 3; i++) {
          products.push({
            key: key + "-" + i,
            name: key + "-" + i,
          });
        }
        callback(products);
      },
    },
  },

  data() {
    return {
      data: [
        {
          key: "A",
          name: "A",
          products: [
            {
              key: "A-1",
              name: "A-1",
              products: [],
              selectedKeys: [],
              selectedProducts: [],
            },
            {
              key: "A-2",
              name: "A-2",
              products: [],
            },
          ],
        },
        {
          key: "B",
          name: "B",
          products: [
            {
              key: "B-1",
              name: "B-1",
              products: [],
            },
            {
              key: "B-2",
              name: "B-2",
              products: [],
            },
          ],
        },
      ],
      productLists: {},
      selectedItems: {},
      selectedIndex: {},
      isShowSelected: false, //是否显示已选
      selectedKeys: [],
    };
  },
  filters: {},
  computed: {
    leval() {
      return this.levalCount - 2;
    },
    dynamicLevalSpans() {
      var spans = [];
      for (let i = 1; i < this.levalSpans.length - 1; i++)
        spans.push(this.levalSpans[i]);

      return spans;
    },
    allSelectedProducts() {
      // 所有选中项
      return this.getAllSeletedProducts();
    },
    tableColums() {
      var colums = [];
      if (this.allSelectedProducts && this.allSelectedProducts.length > 0)
        colums = Object.keys(this.allSelectedProducts[0]).map((k) => {
          return { dataIndex: k, key: k, title: k };
        });

      colums.push({
        title: "Action",
        key: "action",
        scopedSlots: { customRender: "action" },
      });

      return colums;
    },
  },
  watch: {
    allSelectedProducts() {
      this.$emit("selectedChange", this.allSelectedProducts.length);
    },
  },
  methods: {
    // 数据载入回调
    dataLoaderCallback(product, productChildren) {
      if (productChildren && productChildren instanceof Array) {
        productChildren.forEach((item) => {
          this.$set(item, "selectedProducts", []);
          this.$set(item, "selectedKeys", []);
        });
        this.$set(product, "products", productChildren);
      } else this.$set(product, "products", []);
    },
    /**型号点击 */
    productItemClick(product, key, leval) {
      //判断是否已经载入了数据，是则不重新载入
      if (!product.products || product.products.length == 0) {
        //this.$set(product, "products", []);
        //通过外部 loader 获取数据
        //leval+1 是为了方便调用者清楚对应的层级，但是实际上我们只处理  动态层级，即动态载入数据的 层级
        this.dataLoader(product, key, leval + 1, (productChildren) =>
          this.dataLoaderCallback(product, productChildren)
        );
      }
      this.$set(this.productLists, leval, product.products);
      //将当前载入的层级后面的层级的数据置空，不显示
      Object.keys(this.productLists).forEach((k) => {
        if (Number(k) > leval) {
          this.$set(this.productLists, Number(k), []);
        }
      });
    },

    /**选中选项（最后一列） */
    selectItem(product, key, leval) {
      //判断所属的层级选中的项中的选择key 是否包含当前点击的 项，存在则移除，不存在则插入
      var index = this.selectedKeys.indexOf(key);
      if (index > -1) {
        this.selectedKeys.splice(index, 1);
        this.selectedProducts.splice(index, 1);
      } else {
        this.selectedKeys.push(key);
      }
    },
    /*选中所有：当前已选中部分，则清空，否则选中所有 （同时将选中的product记录是为了后面获取选中列表方便）*/
    selectAll(checked, products, leval) {
      if (checked) {
        products.forEach((product) => {
          var index = this.selectedKeys.indexOf(product.key);
          if (index == -1) {
            this.selectedKeys.push(product.key);
          }
        });
      }
    },
    /*获取选中的总数  基于当前 product 子集的选中总数*/
    getSelectedCount(product) {
      let _this = this;
      let count = 0;
      if (!product.products) return count;
      let products = product.products;

      //递归层次计算，实际上主要遍历到最后一层判断 selectedKeys 的长度
      products.forEach((p) => {
        if (p.products && p.products.length > 0) {
          count += _this.getSelectedCount(p);
        }
        if (p.selectedKeys) count += p.selectedKeys.length;
      });
      return count;
    },

    /*获取选中的产品 递归（实际上最后一层 的 selectedProducts ） preproducts 为最后一层之前的每个层级的对象，*/
    getSeletedProducts(preproducts, product, productList) {
      let _this = this;

      if (product.selectedProducts && product.selectedProducts.length > 0) {
        product.selectedProducts.forEach((selectProduct) => {
          let productItem = {
            // key: selectProduct.key,
            // name: selectProduct.name,
            // preProduct: product,
          };
          //遍历之前层级的信息，
          for (let i = 0; i < preproducts.length; i++) {
            productItem["column_name_" + i] = preproducts[i].name;
            productItem["column_key_" + i] = preproducts[i].key;
          }

          productItem.key = selectProduct.key;
          productItem.name = selectProduct.name;
          productItem.preProduct = product;

          productList.push(productItem);
        });
      } else {
        if (product.products && product.products.length > 0) {
          var _preproducts = [].concat(preproducts);

          _preproducts.push(product);
          product.products.forEach((p) => {
            if (p.products && p.products.length > 0) {
              _this.getSeletedProducts(_preproducts, p, productList);
            }
          });
        }
      }
    },

    // 获取所有选中的项
    getAllSeletedProducts() {
      var products = [];
      this.data.forEach((product) => {
        this.getSeletedProducts([], product, products);
      });
      // this.$set(this, "allSelectedProducts", products);
      //this.allSelectedProducts = products;
      // console.log(this.data);
      return products;
    },
    deleteFromAllSeletedProducts(preProduct, key) {
      // 所有选中列表里删除选项
      //借用选项的选中方法，重复选中将移除

      var index = preProduct.selectedKeys.indexOf(key);
      if (index > -1) {
        preProduct.selectedKeys.splice(index, 1);
        preProduct.selectedProducts.splice(index, 1);
      }
    },

    getProductChildren(checked, product, key, leval, children) {
      // 如果是 取最后一级，则选中，
      if (this.leval == leval) {
        this.$set(product, "selectedKeys", []);
        this.$set(product, "selectedProducts", []);

        if (checked) {
          children.forEach((p) => {
            product.selectedKeys.push(p.key);
            product.selectedProducts.push(p);
          });
        }
      } else {
        children.forEach((p) => {
          this.checkAllProductChildren(checked, p, p.key, leval + 1);
        });
      }
    },
    // 选中产品的所有子项
    checkAllProductChildren(checked, product, key, leval) {
      // 递归获取子项，取到最后一项时，将所有数据都选中或者取消选中

      //判断是否已经载入了数据，是则不重新载入
      if (!product.products || product.products.length == 0) {
        //this.$set(product, "products", []);
        //通过外部 loader 获取数据
        //leval+1 是为了方便调用者清楚对应的层级，但是实际上我们只处理  动态层级，即动态载入数据的 层级
        this.dataLoader(product, key, leval + 1, (productChildren) => {
          this.dataLoaderCallback(product, productChildren);
          // 额外处理数据
          this.getProductChildren(
            checked,
            product,
            key,
            leval,
            productChildren
          );
        });
      } else
        this.getProductChildren(checked, product, key, leval, product.products);
    },
    // 选中所有
    checkAllProductList(checked, products, leval) {
      products.forEach((product) => {
        this.checkAllProductChildren(checked, product, product.key, leval);
      });
    },
    // 检查单个产品是否选中
    isCheckAllOfProduct(product, leval) {
      if (!product || !product.products) return false;
      // 递归产品列表判断是否全选
      //

      if (this.leval == leval) {
        if (
          !(
            product.products &&
            product.selectedKeys &&
            product.selectedKeys.length > 0 &&
            product.products.length == product.selectedKeys.length
          )
        )
          return false;
      } else if (this.leval > leval) {
        if (product.products.length == 0) return false;
        for (let i = 0; i < product.products.length; i++) {
          var productItem = product.products[i];
          //倒数第二列，判断是否有子产品或者子产品是否都 选中了

          //递归统计
          if (!this.isCheckAllOfProduct(productItem, leval + 1)) return false;
        }
      }
      return true;
    },
    // 检查选中所有
    isCheckAllOfProductList(products, leval) {
      if (!products) return false;
      for (let i = 0; i < products.length; i++) {
        var productItem = products[i];
        //倒数第二列，判断是否有子产品或者子产品是否都 选中了

        //递归统计
        if (!this.isCheckAllOfProduct(productItem, leval + 1)) return false;
      }
      return true;
    },

    // 索引点击
    indexClick(key) {
      this.selectedIndex = key;
      //TODO 滚动品牌
    },
    // 显示已选

    showSelected() {
      this.isShowSelected = true;
    },
    checkAll(checked) {
      this.checkAllProductList(checked, this.data, -2);
    },
  },
};
</script>

<style scoped lang="less">
.content,
.content-row {
  height: 100%;
}
li {
  list-style-type: none;
}
/* 索引列 */
.col-index {
  background: #f6f7fa;
  text-align: center;
  font-size: 20px;
  font-weight: bold;
  color: #9aa3b6;
}
.col-index {
  ul {
    padding: 0px;
    display: flex;
    flex-direction: column;
  }
  li {
    cursor: pointer;
  }
}
.col-products {
  ul {
    padding: 0px;
    display: flex;
    flex-direction: column;
  }
  li {
    cursor: pointer;
  }
}

/* 选中的产品项 */
.productActive {
  color: coral;
}
</style>
